<?php

  require_once "JooS/Helper/Broker.php";
  
  class JooS_Server_Controller {
    private $_request = null, $_roler = null, $_cacher = null;

    public function __construct() {
    }

    public function getRequest() {
      if (is_null($this->_request))
        $this->_request = JooS_Server::getInstance()->getRequest();
      return $this->_request;
    }

    public function getResponse() {
      $request = $this->getRequest();
      $requestPath = $request->getResourcePath();
      $requestAction = $request->getResourceAction();
      $requestPresentation = $request->getResourcePresentation();

      $get = ( $request->getMethod() == "GET");

      $responseCacheble = false;
      $responseCode = 200;
      $responseHeaders = null;
      $responseBody = $get ? $this->getCacher()->load($this->getCacheKey()) : null;
      $resource = null;

      try {
        require_once "JooS/Server/Presentation.php";
        $presentation = JooS_Server_Presentation::factory($requestPresentation);

        if ($responseBody === null) {
          try {
            require_once "JooS/Server/Resource.php";

            $methodName = $requestAction . "Action";
            if (!is_callable(array($this, $methodName)))
              self::throwException("Method " . get_class($this) . "::" . $requestAction . "Action does not exists", 404);

            $resource = $this->{$methodName}();

            if (is_array($resource))
              $resource = new JooS_Server_Resource($resource, $this);
            elseif ( !($resource instanceof JooS_Server_Resource) )
              self::throwException("Method " . get_class($this) . "::" . $requestAction . "Action must return JooS_Server_Resource or array", 503);

            if ($get)
              $responseCacheble = true;
          }
          catch (JooS_Server_Controller_Exception $e) {
            $responseCode = $e->getCode();
            $responseHeaders = $e->getHeaders();
            $resource = new JooS_Server_Resource(array(
              "error" => array(
                "code" => $e->getCode(), 
                "message" => $e->getMessage(), 
                "data" => $e->getData()
              )
            ), $this);
          }
        }

        $responseBody = $presentation->getBody($resource);
      }
      catch (JooS_Server_Presentation_Exception $e) {
        // @toTest
        $presentation = new JooS_Server_Presentation($requestPresentation);

        $responseCode = $e->getCode();
        $responseHeaders = null;
        $responseBody = $e->getMessage();
      }

      if ($responseHeaders === null) {
        $responseHeaders = array(
          "Content-Type" => $presentation->getContentType() . "; charset=" . ini_get("default_charset"), 
          "Content-Length" => strlen($responseBody)
        );
      }

      if ($responseCacheble)
        $this->getCacher()->save($this->getCacheKey(), $responseBody);

      require_once "JooS/Server/Response.php";
      return new JooS_Server_Response($responseCode, $responseHeaders, $responseBody);
    }

    public function getControllerName() {
      return get_class($this);
    }

    public function getCacheKey() {
      $r = $this->getRequest();

      $cacheKey = implode("~", array(
        $this->getRoler()->get(), 
        $r->getHost(), 
        $r->getRequestUri()
      ));
      return $cacheKey;
    }

    public function getCacher() {
      if (null === $this->_cacher) {
        $_cacher = JooS_Helper_Broker::helperBroker()->Server_Controller_SettingsHelper->getCacher();
        if ($_cacher instanceof JooS_Server_Cacher_Interface)
          $this->_cacher = $_cacher;
        else
          self::throwException("Server_Cacher must implement JooS_Server_Cacher_Interface");
      }
      return $this->_cacher;
    }

    public function getRoler() {
      if (null === $this->_roler) {
        $_roler = JooS_Helper_Broker::helperBroker()->Server_Controller_SettingsHelper->getRoler();
        if ($_roler instanceof JooS_Server_Roler_Interface)
          $this->_roler = $_roler;
        else
          self::throwException("Server_Cacher must implement JooS_Server_Roler_Interface");
      }
      return $this->_roler;
    }

    protected static function throwException($message, $code, $data = array(), $headers = array()) {
      require_once "JooS/Server/Controller/Exception.php";

      $Exception = new JooS_Server_Controller_Exception($message, $code);
      throw $Exception->setData($data)->setHeaders($headers);
    }
  }

?>